/*
 * Copyright 2007 National Bioinformatics Network
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package dgbgui;

import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashSet;
import java.util.Properties;

import javax.swing.Icon;
import javax.swing.ImageIcon;

import dgbgui.actions.ActionEnabler;
import dgbgui.actions.ActionRepository;
import dgbgui.command.CommandStack;
import dgbgui.gui.DefaultCanvasScene;
import dgbgui.gui.MainFrame;
import dgbgui.gui.ModelDrivenOutlineScene;
import dgbgui.logging.ErrorLogger;
import dgbgui.modeldocument.ModelDocument;
import dgbgui.modeldocument.ModelDrivenWorkspace;
import dgbgui.modeldocument.Query;
import dgbgui.modeldocument.ResultStore;
import dgbgui.selection.SelectionManager;



public class DGBGUI  {
    

    @SuppressWarnings("serial")
    public class DGBProperties extends Properties {
        public void addDefaults() {
            if ( getProperty("IOR") == null ) {
                put("IOR", "IOR:010000001C00000049444C3A646762434F5242412F69496E746572666163653A312E3000010000000000000028000000010101000A0000003132372E302E302E310061DF09000000434C0100EEC9D5293100000000000000");
            }
        }
    }
    
    private void readProperties() {
        // Load last set properties 
        try {
            FileInputStream in = new FileInputStream(m_dgbPropertiesFilename); 
            m_dgbProps.load(in);
            in.close();
        } catch ( Exception ex) {
            System.out.println("DGB Properties not found, using defaults.");
        } 
    }

    public void writeProperties() {
        try {
            FileOutputStream out = new FileOutputStream(m_dgbPropertiesFilename);
            m_dgbProps.store(out, "---dgb connection properties---");
            out.close();
        } catch (Exception exp) {
            System.out.println("Error writing dgb properties");
        }
    }
    
    // Private for singleton 
    private DGBGUI() {
        // Do nothing extra;
    }
        
    
    private void init() {

        // Try to read the properties, then add those items that were not read,
        // or hve been added to a previous version of the properties file
        m_dgbProps = new DGBProperties();
        readProperties();
        m_dgbProps.addDefaults();
        
        // Initialise all the actions before creating the GUI elements
        ActionRepository.getInstance().initAllActions();

        // Create the main frame, scenes and add observation connections
        m_mainFrame = new MainFrame();
        
        DefaultCanvasScene defaultScene = DefaultCanvasScene.getInstance();
        ModelDrivenOutlineScene modelDrivenOutlineScene = ModelDrivenOutlineScene.getInstance();
        
        
        // Default Scene -> Result Store. Outline -> Result store. Result inspector -> Result store
        ResultStore.getInstance().addObserver(defaultScene);
        ResultStore.getInstance().addObserver(modelDrivenOutlineScene);
        ResultStore.getInstance().addObserver(m_mainFrame.getModelDrivenResultsInspector());
       
        // Scenes -> Model Document
        ModelDocument.getInstance().addObserver(defaultScene);
        ModelDocument.getInstance().addObserver(modelDrivenOutlineScene);
        
        
        // Ouline scene -> model driven workspace
        ModelDrivenWorkspace.getInstance().addObserver(modelDrivenOutlineScene);
        
        // Scenes -> Selection
        SelectionManager.getInstance().addObserver(defaultScene);
        SelectionManager.getInstance().addObserver(modelDrivenOutlineScene);

        // Selection inspector, Model DrivenInspector -> selection manager, MD Results Inspector
        SelectionManager.getInstance().addObserver(m_mainFrame.getSelectionInspector());
        SelectionManager.getInstance().addObserver(m_mainFrame.getModelDrivenInspector());
        
        
        // Views -> scenes
        defaultScene.addObserver(m_mainFrame.getDefaultCanvasView());
        modelDrivenOutlineScene.addObserver(m_mainFrame.getModelDrivenOutlineView());
        
        // The action enabler observers the model document, selection manager
        // and command stack
        SelectionManager.getInstance().addObserver(ActionEnabler.getInstance());
        ModelDocument.getInstance().addObserver(ActionEnabler.getInstance());
        CommandStack.getInstance().addObserver(ActionEnabler.getInstance());
        
        // Set the clipbaord to blank
        ModelDocument.getInstance().setClipBoard(new HashSet<Query>());
        
        // Create the error logger and add the error inspector 
        // as an observer
        ErrorLogger.getInstance().addObserver(m_mainFrame.getErrorInspector());
        
        // Try and initialise the types of startup
        ModelDocument.getInstance().initialiseTypesAndModels();
 
        m_mainFrame.pack();
        //m_mainFrame.setSize (new Dimension (800, 600));
        m_mainFrame.setVisible (true);
        // No gui code should be run after this
    }
    
    public static Icon getIcon(String filename, String description) {
        return createAppletImageIcon(filename,description);
    }
    
    private static ImageIcon createAppletImageIcon(String filename, String description) {
        Image image = getImage(filename);
        if ( image != null ) {
            return new ImageIcon(image,description);
        } else {
            return null;
        }
    }
    
    public static Image getImage(String filename) {

        URL url = DGBGUI.class.getResource("images/" + filename);
        Image returnedImage = null;
        if ( url != null ) {
            returnedImage =  Toolkit.getDefaultToolkit().createImage(url);
        } 

        // If null, show an error
        if ( returnedImage == null ) {
            System.err.println("Couldn't load image \"" + filename + "\"");
        }
        return returnedImage;
    }

    
    public MainFrame getMainFrame() {
    	return m_mainFrame;
    }
    
    public static DGBGUI getInstance() {
    	return m_instance;
    }
    
    public DGBProperties getDGBProperties() {
        return m_dgbProps;
    }
    
    public void setDGBProperties(DGBProperties properties) {
        m_dgbProps = properties;
        writeProperties();
    }
    

    /**
     * Get the IOR via HTTP, and set it as a application property
     */
    public boolean getIORViaHTTP() {
        
        DGBGUI.DGBProperties properties = DGBGUI.getInstance().getDGBProperties();
        
        InputStream  in = null;
        try {
            URL url = new URL("http://trac.nbn.ac.za/dgbgui/chrome/site/files/ior");
            URLConnection conn = null;
            conn = url.openConnection();
            in = conn.getInputStream();
            byte[] buffer = new byte[1024];
            int count;
            String IORString = "";
            while ((count = in.read(buffer)) != -1) {
                for ( int k = 0; k < count; ++k ) {
                    IORString += (char)buffer[k];
                }
            }
            
            properties.put("IOR", IORString);
            setDGBProperties(properties);
            System.out.println("Setting IOR: " + IORString);
            return true;
        } catch (Exception exception) {
            ErrorLogger.getInstance().logException(exception);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException ioe) {
                ErrorLogger.getInstance().logException(ioe);
            }
        }
        return false;
    }
    
    
    /**
     * @param dialog Centre the dialog on the application window
     */
    public static void centerDialog(Dialog dialog) {
        Dimension dialogDimensions = dialog.getSize();
        Dimension mainFrameDimensions = m_instance.m_mainFrame.getSize();
        Point absoluteMainFrameLocation = m_instance.m_mainFrame.getLocationOnScreen();
        
        Point relativeDialogPosition = new Point(
                absoluteMainFrameLocation.x + mainFrameDimensions.width/2 - dialogDimensions.width/2,
                absoluteMainFrameLocation.y + mainFrameDimensions.height/2 - dialogDimensions.height/2);
                
        // If the dialog is now off-screen, put it at 0,0
        if ( relativeDialogPosition.x < 0 ) {
            relativeDialogPosition.x = 0;
        }
        if ( relativeDialogPosition.y < 0 ) {
            relativeDialogPosition.y = 0;
        }
        dialog.setLocation(relativeDialogPosition);
        
    }
    
    public static void main(String[] argv) {
    	
    	//Schedule a job for the event-dispatching thread:
    	//creating and showing this application's GUI.
    	javax.swing.SwingUtilities.invokeLater(new Runnable() {
    		public void run() {
    			m_instance = new DGBGUI();
                // Done in two stages so if the instance is references
                // during initialisation, it already exists;
                m_instance.init();
    		}
            

    	});
    }

    
    private static DGBGUI m_instance;
    private DGBProperties m_dgbProps;
    private MainFrame m_mainFrame;
    private static String m_dgbPropertiesFilename = "dgbProperties";


    
    
} // end of class DGBGUI


